/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package pdf;

import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.PageSize;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfWriter;
import com.openbrew.openbrewrf.Administration;
import com.openbrew.openbrewrf.BoilHops;
import com.openbrew.openbrewrf.CommonBrewSupplies;
import com.openbrew.openbrewrf.DryHops;
import com.openbrew.openbrewrf.MaltBill;
import com.openbrew.openbrewrf.MashStep;
import com.openbrew.openbrewrf.RecipeAdditives;
import com.openbrew.openbrewrf.Recipes;
import com.openbrew.openbrewrf.SelectedSalt;
import com.openbrew.openbrewrf.WaterSalts;
import com.openbrew.openbrewrf.views.POSSupplyView;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.io.OutputStream;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import service.enumerations.MashType;
import utils.Calcs;
import utils.HopsCalculations;

/**
 *
 * @author dchapman
 */
public class RecipePDFCreator {

    // Create Number Formater for displaying numbers.
    private final NumberFormat f2 = new DecimalFormat("#0.00");
    private final NumberFormat f0 = new DecimalFormat("#0");
    private final NumberFormat f3 = new DecimalFormat("#0.000");
    
    //Variable to set page borders.
    final int borderSize = 50;
    
    public void createPDF(OutputStream outputStream, final Recipes recipe, final Administration admin){
        try{
            Document document = new Document(PageSize.A4, borderSize, borderSize, borderSize, borderSize);
            //PdfWriter.getInstance(document, outputStream);   
            PdfWriter writer = PdfWriter.getInstance(document, outputStream);
            document.open();
            PdfContentByte canvas = writer.getDirectContent();
            // Create the Graphics2D object.
            Graphics2D g2d = canvas.createGraphics(PageSize.A4.getWidth(), PageSize.A4.getHeight());
            
            //Create page 1 image
            makeRecipeView(g2d, recipe, admin);
            
            g2d.dispose();
            document.close();
        }catch(DocumentException ex){
            
        }
    }
    
    private void makeRecipeView(final Graphics2D g2d, final Recipes recipe, final Administration admin){
        // Set the default drawing color to black.
        g2d.setPaint(Color.BLACK);

        // ---Section 1 (Header)
        // Print the header
        final String titleText = admin.getBreweryName();
        final Font titleFont = new Font("helvetica", Font.BOLD, 12);
        g2d.setFont(titleFont);

        // Comput the right alignment on the page.
        FontMetrics fontMetrics = g2d.getFontMetrics();
        final double titleX = (PageSize.A4.getWidth()-borderSize) - (fontMetrics.stringWidth(titleText));
        final double titleY = 18+borderSize;
        g2d.drawString(titleText, (int) titleX, (int) titleY);

        // Print the address.
        final String addressText0 = "Recipe: " + recipe.getRName() + " Rev - " + Integer.toString(recipe.getRRev());
        final String addressText1 = "RID#" + Integer.toString(recipe.getRid());
        final Font addressFont = new Font("helvetica", Font.PLAIN, 8);
        final int linespace = 10;
        final int doublespace = 20;
        final int addressY = 18+borderSize;
        g2d.setFont(addressFont);

        // Compute the right alignment for the address info.
        fontMetrics = g2d.getFontMetrics();
        double addressX = (PageSize.A4.getWidth()- borderSize) - (fontMetrics.stringWidth(addressText0));
        g2d.drawString(addressText0, (int) addressX, (addressY + (linespace * 1)));
        addressX = (PageSize.A4.getWidth()- borderSize) - (fontMetrics.stringWidth(addressText1));
        g2d.drawString(addressText1, (int) addressX, (addressY + (linespace * 2)));

        final Font regularFont = new Font("helvetica", Font.PLAIN, 8);
        final Font boldFont = new Font("helvetica", Font.BOLD, 8);

        // Set up columns.
        final double col1 = borderSize;
        final double col2 = ((PageSize.A4.getWidth()-borderSize) / 8) * 3;
        final double col3 = ((PageSize.A4.getWidth()-borderSize) / 8) * 4;
        final double col4 = ((PageSize.A4.getWidth()-borderSize) / 8) * 5;
        final double col5 = ((PageSize.A4.getWidth()-borderSize) / 8) * 6;

        // Variables for use during calculation of recipes.
        final double GUtot = (Calcs.platotoSpecificGravity((double)recipe.getRgt()) - 1) * 1000 * recipe.getRVol() * 31;
        final double VolFinal = recipe.getRVol() * 31;

        double LBTOT = 0;
        double LBNM = 0;
        double SRMTOT = 0;

        // ---Section 2 (Malt)
        int maltY = 25+borderSize;
        String text = "";
        maltY += doublespace;

        g2d.setFont(regularFont);
        if(admin.getBPlato()){
            text = "Target Gravity = " + f2.format(recipe.getRgt());
        } else {
            text = "Target Gravity = " + f3.format(Calcs.platotoSpecificGravity((double)recipe.getRgt()));
        }
        g2d.drawString(text, borderSize, maltY);

        maltY += linespace;
        text = "Target Volume = " + f2.format(recipe.getRVol()) + " BBL";
        g2d.drawString(text, borderSize, maltY);

        // Get Malt data if id is chosen.
        double lbs = 0;
        double srm = 0;
        double bagnum = 0;
        double remain = 0;

        maltY += doublespace;
        g2d.setFont(boldFont);
        text = "Malt";
        g2d.drawString(text, borderSize, maltY);
        maltY += linespace;
        g2d.setFont(boldFont);
        text = "Malt Type:";
        g2d.drawString(text, (int) col1, maltY);
        text = "Percent:";
        g2d.drawString(text, (int) col2, maltY);
        text = "Pounds:";
        g2d.drawString(text, (int) col3, maltY);
        text = "Efficiency:";
        g2d.drawString(text, (int) col4, maltY);
        text = "Bags, Lbs.:";
        g2d.drawString(text, (int) col5, maltY);

        g2d.setFont(regularFont);
        final List<MaltBill> maltBill = recipe.getMaltBillCollection();
        if(maltBill != null){
            for (final MaltBill maltPair : maltBill){
                if(maltPair.getMaltID() != null){
                    maltY += linespace;
                    text = maltPair.getMaltID().getMaltName();
                    g2d.drawString(text, (int) col1, maltY);

                    text = f0.format(maltPair.getMaltPercent()) + "%";
                    g2d.drawString(text, (int) col2, maltY);

                    lbs = maltPair.getMaltLbs();
                    text = f2.format(lbs) + " Lbs.";
                    g2d.drawString(text, (int) col3, maltY);

                    text = f2.format(maltPair.getMaltID().getMaltEff()) + "%";
                    g2d.drawString(text, (int) col4, maltY);

                    bagnum = Math.floor(lbs / maltPair.getMaltID().getMaltBagLbs());
                    remain = lbs - (bagnum * maltPair.getMaltID().getMaltBagLbs());
                    text = f0.format(bagnum) + " Bags, " + f2.format(remain) + " Lbs.";
                    g2d.drawString(text, (int) col5, maltY);

                    srm = (maltPair.getMaltID().getMaltColor() * lbs) / VolFinal;
                    if (maltPair.getMaltID().getMaltEff() == 100) {
                        LBNM += lbs;
                    }
                    else {
                        LBTOT += lbs;
                        LBNM += lbs;
                    }
                    SRMTOT += srm;
                }
            }
        }

        // Print out total stats.
        srm = ((SRMTOT * 0.3) + 4.7);
        maltY += doublespace;
        text = "Color: " + f2.format(srm);
        g2d.drawString(text, (int) col1, maltY);
        text = "Mash Total: " + f2.format(LBTOT) + " Lbs.";
        g2d.drawString(text, (int) col2, maltY);
        text = "Total Pounds: " + f2.format(LBNM) + " Lbs.";
        g2d.drawString(text, (int) col4, maltY);

        // ---SECTION 3: Water Data
        maltY += doublespace;
        g2d.setFont(boldFont);
        text = "Water Additions:";
        g2d.drawString(text, borderSize, maltY);
        g2d.setFont(regularFont);
        maltY += linespace;
        if(recipe.getRecipeSaltID()!=null && recipe.getRecipeSaltID().getSelectedSaltCollection()!=null){
            for(final SelectedSalt ss : recipe.getRecipeSaltID().getSelectedSaltCollection()){
                WaterSalts ws = ss.getWaterSaltID();
                text = ws.getCommonName() + " (" + ws.getMolecularName() + "): " 
                        + f3.format(ss.getSelectedSaltGrams()) + " grams / " 
                        + f3.format(Calcs.gramstoLbs(ss.getSelectedSaltGrams())) + " lbs";
                g2d.drawString(text, (int) col1, maltY);
                maltY += linespace;
            }
        } else {
            text = "Not Applicable";
            g2d.drawString(text, (int) col1, maltY);
        }

        // ---SECTION 4: Hop Data
        // Calculations for Hops
        final double BoilVol = ((VolFinal + 0.5) / (0.96 * 0.9542));
        final double Gstart = ((GUtot / BoilVol) + 1000) / 1000;
        double CGRAV = (1 + ((Gstart - 1.05) / 2));
        if ((1 + ((Gstart - 1.05) / 2)) < 1) {
                CGRAV = 1;
        }
        double IBUTOT = 0;
        double NumBitter = 0;

        // Calculate total IBU from recipe that are not bittering hops.
        double HopNumber = 0;
        float HopAcid = 0;
        double OldIBU = 0;

        double eff = 0;
        double ibu = 0;

        final List<BoilHops> boilHops = recipe.getBoilHopCollection();
        Collections.sort(boilHops, new Comparator<BoilHops>(){
            @Override
            public int compare(BoilHops h1, BoilHops h2){
                if(h1.getBoilHopMinutes()>h2.getBoilHopMinutes()) return -1;
                if(h1.getBoilHopMinutes()<h2.getBoilHopMinutes()) return 1;
                return 0;
            }    
        });
        int hopCount = 0;
        for (final BoilHops boilHop : boilHops){
            if(boilHop.getHopID() != null){
                eff = HopsCalculations.getHopUtilization(boilHop.getHopID().getHopWhole(), (long) boilHop.getBoilHopMinutes());
                ibu = ((((double) boilHop.getBoilHopLbs() * 16) * eff * ((double) boilHop.getHopID().getHopAA() / 100) * 7489) / (VolFinal * CGRAV));
                if(hopCount<1){
                    if ((boilHop.getBoilHopMinutes()< 60) || (boilHop.getBoilHopMinutes() > 80)) {
                        IBUTOT += ibu;
                    } else {
                        NumBitter++;
                        HopNumber = boilHop.getHopID().getHid();
                        HopAcid = boilHop.getHopID().getHopAA();
                        OldIBU = ibu;
                    }
                } else {
                    if ((boilHop.getBoilHopMinutes() < 60) || (boilHop.getBoilHopMinutes() > 80)) {
                        IBUTOT += ibu;
                    } else {
                        NumBitter++;
                        if (HopAcid <= boilHop.getHopID().getHopAA()) {
                            HopNumber = boilHop.getHopID().getHid();
                            HopAcid = boilHop.getHopID().getHopAA();
                            IBUTOT += OldIBU;
                        } else {
                            IBUTOT += ibu;
                        }
                        OldIBU = ibu;
                    }
                }
            }
            hopCount++;
        }

        final double IBULEFT = recipe.getRibu() - IBUTOT;
        IBUTOT = 0;

        // Print out Hops.
        maltY += doublespace;
        g2d.setFont(boldFont);
        text = "Kettle Additions:";
        g2d.drawString(text, borderSize, maltY);

        double lbdisp = 0;
        remain = 0;

        maltY += linespace;
        text = "Name:";
        g2d.drawString(text, (int) col1, maltY);
        text = "Alpha %:";
        g2d.drawString(text, (int) col2, maltY);
        text = "Time:";
        g2d.drawString(text, (int) col3, maltY);
        text = "Pounds:";
        g2d.drawString(text, (int) col4, maltY);
        text = "Lbs., Oz.:";
        g2d.drawString(text, (int) col5, maltY);
        g2d.setFont(regularFont);

        float tempLbs = 0;

        Collections.sort(admin.getCbsCollection(), new Comparator<CommonBrewSupplies>(){
            @Override
            public int compare(CommonBrewSupplies c1, CommonBrewSupplies c2){
                if(c1.getBoilTime()<c2.getBoilTime()) return -1;
                if(c1.getBoilTime()>c2.getBoilTime()) return 1;
                return 0;
            }    
        });

        hopCount = 0;
        int count = 0;
        if(admin.getCbsCollection()!=null){
            count = admin.getCbsCollection().size()-1;
        }
        for (final BoilHops boilHop : boilHops){
            if(boilHop.getHopID()!=null){
                boolean add = true;
                int time = (int)boilHop.getBoilHopMinutes();
                if(count>=0){
                    while(add){
                        int kTime = admin.getCbsCollection().get(count).getBoilTime();
                        if(kTime>time){
                            maltY += linespace;
                            final POSSupplyView supply = admin.getCbsCollection().get(count).getSupplyID();
                            text = "Addition - " + supply.getSupName();
                            g2d.drawString(text, (int) col1, maltY);

                            text = Integer.toString(kTime) + " min";
                            g2d.drawString(text, (int) col3, maltY);

                            text = Float.toString(admin.getCbsCollection().get(count).getAmount()) 
                                    + " " + admin.getCbsCollection().get(count).getUnits();
                            g2d.drawString(text, (int) col4, maltY);

                            count = count - 1;
                        } else {
                            add = false;
                        }
                    } 
                }
                eff = HopsCalculations.getHopUtilization(boilHop.getHopID().getHopWhole(), (long) boilHop.getBoilHopMinutes());
                if ((boilHop.getBoilHopMinutes() < 80) && (boilHop.getBoilHopMinutes() > 60) && hopsEqual(boilHop.getHopID().getHopAA(), HopAcid)) {
                    ibu = IBULEFT;
                    tempLbs = (float) (((ibu * VolFinal * CGRAV) / (7489 * eff * (boilHop.getHopID().getHopAA() / 100))) / 16);
                }else {
                    ibu = (((boilHop.getBoilHopLbs() * 16) * eff * (boilHop.getHopID().getHopAA() / 100) * 7489) / (VolFinal * CGRAV));
                }
                maltY += linespace;
                text = "Hop - " + boilHop.getHopID().getHopName();
                g2d.drawString(text, (int) col1, maltY);
                text = Float.toString(boilHop.getHopID().getHopAA()) + "%";
                g2d.drawString(text, (int) col2, maltY);
                if(hopCount < 2){
                    if(boilHop.getBoilHopFWH()){
                        text = "FWH";
                        g2d.drawString(text, (int) col3, maltY);
                    }else{
                        text = Float.toString(boilHop.getBoilHopMinutes()) + " min";
                        g2d.drawString(text, (int) col3, maltY);
                    }
                } else {
                    text = Float.toString(boilHop.getBoilHopMinutes()) + " min";
                    g2d.drawString(text, (int) col3, maltY);
                }
                if(tempLbs != 0){
                    text = f2.format(tempLbs) + " Lbs.";
                    tempLbs = 0;
                } else {
                    text = f2.format(boilHop.getBoilHopLbs()) + " Lbs.";
                }
                g2d.drawString(text, (int) col4, maltY);
                if(tempLbs != 0){
                    lbdisp = Math.floor(tempLbs);
                    remain = 16 * (tempLbs - lbdisp);
                } else {
                    lbdisp = Math.floor(boilHop.getBoilHopLbs());
                    remain = 16 * (boilHop.getBoilHopLbs() - lbdisp);
                }
                text = (Double.toString(lbdisp) + " Lbs., " + f2.format(remain) + " Oz.");
                g2d.drawString(text, (int) col5, maltY);
                IBUTOT += ibu;
            }
            hopCount++;
        }

        while(count >= 0){
            maltY += linespace;
            int kTime = admin.getCbsCollection().get(count).getBoilTime();
            final POSSupplyView supply = admin.getCbsCollection().get(count).getSupplyID();
            text = "Addition - " + supply.getSupName();
            g2d.drawString(text, (int) col1, maltY);

            text = Integer.toString(kTime) + " min";
            g2d.drawString(text, (int) col3, maltY);

            text = Float.toString(admin.getCbsCollection().get(count).getAmount()) 
                    + " " + admin.getCbsCollection().get(count).getUnits();
            g2d.drawString(text, (int) col4, maltY);

            count = count - 1;
        }

        maltY += doublespace;
        text = "Total IBUs = " + f2.format(IBUTOT);
        g2d.drawString(text, borderSize, maltY);

        // Print out Mash Info.
        maltY += doublespace;
        g2d.setFont(boldFont);
        text = "Mash:";
        g2d.drawString(text, borderSize, maltY);
        g2d.setFont(regularFont);
        maltY += linespace;

        double totalWater = 0;
        double tInitial = 68;
        final double tBoil = 210;
                            
        for(MashStep step : recipe.getMashSchedule().getMashStepCollection()){
            
            Collections.sort(recipe.getMashSchedule().getMashStepCollection(), new Comparator<MashStep>(){
                @Override
                public int compare(MashStep h1, MashStep h2){
                    if(h1.getTemperature()>h2.getTemperature()) return 1;
                    if(h1.getTemperature()<h2.getTemperature()) return -1;
                    return 0;
                }    
            });
            
            
            if(step.getMashType() == MashType.SINGLE_INFUSION.getType()){
                text = "Single Infusion:";
                g2d.drawString(text, (int) col1, maltY);
                maltY += linespace;

                text = "  Ratio (Qts/Lb) = " + f2.format(step.getRatio());
                g2d.drawString(text, (int) col1, maltY);
                final double mashWater = ((step.getRatio() * LBTOT));
                final double waterTemp = (((0.2 / step.getRatio()) 
                        * (step.getTemperature() - tInitial)) + step.getTemperature());
                text = "  Mash Water Volume = " + f2.format(mashWater/4/31) + " BBL";
                g2d.drawString(text, (int) col3, maltY);
                maltY += linespace;

                text = "  Target Temp = " + f2.format(step.getTemperature()) + "°F";
                g2d.drawString(text, (int) col1, maltY);
                text = "  Mash Water Temp = " + f2.format(waterTemp) + "°F";
                g2d.drawString(text, (int) col3, maltY);
                maltY += linespace;

                text = "  Rest Time = " + f2.format(step.getMinutes()) + " min.";
                g2d.drawString(text, (int) col1, maltY);
                maltY += linespace;

                totalWater += mashWater;
                tInitial = step.getTemperature();
            } else if(step.getMashType() == MashType.SPARGE.getType()){
                text = "Sparge:";
                g2d.drawString(text, (int) col1, maltY);
                maltY += linespace;

                text = "  Sparge Water Temp = " + f2.format(step.getTemperature()) + "°F";
                g2d.drawString(text, (int) col1, maltY);
            } else if(step.getMashType() == MashType.STEP.getType()){
                text = "Step:";
                g2d.drawString(text, (int) col1, maltY);
                maltY += linespace;

                final double newTemp = (double)step.getTemperature();
                double amt = (newTemp - tInitial)*(((0.2*LBTOT)+(totalWater))/(tBoil - newTemp));
                text = "  Target Temp = " + f2.format(step.getTemperature()) + "°F";
                g2d.drawString(text, (int) col1, maltY);
                text = "  Water Addition = " + f2.format(amt/4/31) + " BBL @ " + f2.format(tBoil) + "°F";
                g2d.drawString(text, (int) col3, maltY);
                maltY += linespace;

                text = "  Rest Time = " + f2.format(step.getMinutes()) + " min.";
                g2d.drawString(text, (int) col1, maltY);
                maltY += linespace;

                totalWater += amt;
                tInitial = step.getTemperature();
            } else if(step.getMashType() == MashType.DECOCTION.getType()){
                text = "Decoction:";
                g2d.drawString(text, (int) col1, maltY);
                maltY += linespace;

                final double newTemp = (double)step.getTemperature();
                double amt = ((0.2*LBTOT)+totalWater) * ((newTemp - tInitial)/(tBoil - tInitial - 10));
                text = "  Target Temp = " + f2.format(step.getTemperature()) + "°F";
                g2d.drawString(text, (int) col1, maltY);
                text = "  Decoction = " + f2.format(amt/4/31) + " BBL @ " + f2.format(tBoil) + "°F";
                g2d.drawString(text, (int) col3, maltY);
                maltY += linespace;

                text = "  Rest Time = " + f2.format(step.getMinutes()) + " min.";
                g2d.drawString(text, (int) col1, maltY);
                maltY += linespace;

                totalWater += amt;
                tInitial = step.getTemperature();
            }
        }

        // Print out Yeast Info.
        maltY += doublespace;
        g2d.setFont(boldFont);
        text = "Yeast:";
        g2d.drawString(text, borderSize, maltY);
        g2d.setFont(regularFont);
        maltY += linespace;
        text = "Yeast = " + recipe.getYeastName().getYeastName();
        g2d.drawString(text, (int) col1, maltY);
        text = "Fermentation Temp = " + f2.format(recipe.getPTemp()) + "°F";
        g2d.drawString(text, (int) col3, maltY);

        final List<DryHops> dryHops = recipe.getDryHopCollection();

        if(checkForDryHops(dryHops)){
            // Print out Dry Hopping.
            maltY += doublespace;
            g2d.setFont(boldFont);
            text = "Dry Hopping:";
            g2d.drawString(text, borderSize, maltY);
            maltY += linespace;
            text = "Hop Name:";
            g2d.drawString(text, (int) col1, maltY);
            text = "Days:";
            g2d.drawString(text, (int) col2, maltY);
            text = "Pounds:";
            g2d.drawString(text, (int) col3, maltY);
            g2d.setFont(regularFont);


            for(DryHops dryHop : dryHops){
                if(dryHop.getHopID()!=null){
                    maltY += linespace;
                    text = dryHop.getHopID().getHopName();
                    g2d.drawString(text, (int) col1, maltY);
                    text = Integer.toString(dryHop.getDryHopDays());
                    g2d.drawString(text, (int) col2, maltY);
                    text = f2.format(dryHop.getDryHopLbs());
                    g2d.drawString(text, (int) col3, maltY);
                }
            }
        }

        final List<RecipeAdditives> safs = recipe.getAdditiveCollection();

        if(checkForSpices(safs)){
            // Print out Spices and Flavorings.
            maltY += doublespace;
            g2d.setFont(boldFont);
            text = "Spice and flavoring:";
            g2d.drawString(text, borderSize, maltY);
            maltY += linespace;
            text = "Spice / Flavor:";
            g2d.drawString(text, (int) col1, maltY);
            text = "Amount:";
            g2d.drawString(text, (int) col2, maltY);
            text = "Notes:";
            g2d.drawString(text, (int) col3, maltY);
            g2d.setFont(regularFont);
            for(final RecipeAdditives saf : safs){
                if(saf.getSupply()!=null){
                    final POSSupplyView supply = saf.getSupply();
                    maltY += linespace;
                    text = supply.getSupName();
                    g2d.drawString(text, (int) col1, maltY);
                    text = f2.format(saf.getAdditiveLbs()) + " " + saf.getAdditiveUnits();
                    g2d.drawString(text, (int) col2, maltY);
                    text = saf.getAdditiveNotes();
                    g2d.drawString(text, (int) col3, maltY);
                }
            }
        }
                            
        maltY += doublespace;
        g2d.setFont(boldFont);
        text = "Recipe Notes:";
        g2d.drawString(text, borderSize, maltY);
        g2d.setFont(regularFont);
                            
        for(final String line : recipe.getNotes().split("\n")){
            maltY += linespace;
            int curX = borderSize;
            String[] words = line.split(" ");
            for(String word : words){
                int wordWidth = fontMetrics.stringWidth(word + " ");
                if(curX + wordWidth >= borderSize + 500){
                    maltY += linespace;
                    curX = borderSize;
                }
                g2d.drawString(word, curX, maltY);
                curX += wordWidth;
            }
        }
    }

    private static boolean hopsEqual(final float hopA, final float hopB) {
        final float error = 0.001f;
        return (Math.abs(hopA - hopB) < error);
    }
            
    private boolean checkForDryHops(final List<DryHops> dryHops){
        boolean retVal = false;
        if(dryHops!=null){
            for(final DryHops dh : dryHops){
                if(dh.getHopID() != null){
                    retVal = true;
                }
            }
        }
        return retVal;
    }
            
    private boolean checkForSpices(final List<RecipeAdditives> safs){
        boolean retVal = false;
        if(safs!=null){
            for(final RecipeAdditives saf : safs){
                if(saf.getSupply() != null){
                    retVal = true;
                }
            }
        }
        return retVal;
    }
    
}
